import {register} from "@antv/x6-vue-shape";
import TaskNode from "@/components/TaskNode.vue";
import {Graph} from "@antv/x6";
import {NodeStatus} from "@/enum/NodeStatus.ts";
import {Snapline} from "@antv/x6-plugin-snapline";
import {Selection} from "@antv/x6-plugin-selection";
import {TaskInfo} from "@/api/TaskApi.ts";
import {Stencil} from "@antv/x6-plugin-stencil";
import { nodeTemplateList } from "@/data/TaskData.ts";

const stencilGroup = {
    name: 'group',
    title: 'Group',
    collapsable: false
}

export const commonPorts = {
    items: [
        {
            group: 'left',
        },
        {
            group: 'right',
        }
    ],
}

const shapeName:string = 'task-node'
const stencilTitle:string = '任务节点'

// 注册节点
export const handleRegisterNode = () => {
    register({
        shape: shapeName,
        width: 110,
        height: 40,
        component: TaskNode,
        ports: {
            groups: {
                left: {
                    position: 'left',
                    attrs: {
                        circle: {
                            magnet: true,
                            stroke: '#8f8f8f',
                            r: 5,
                        },
                    },
                },
                right: {
                    position: 'right',
                    attrs: {
                        circle: {
                            magnet: true,
                            stroke: '#8f8f8f',
                            r: 5,
                        },
                    },
                },
            },
        },
    })
}

// 创建编辑画板
const buildEditGraph = (graphDom: HTMLElement) => {
    return new Graph({
        container: graphDom,
        autoResize: true,
        background: {
            color: '#F2F7FA',
        },
        panning: true, // 平移
        mousewheel: false, // 缩放
        connecting: {
            allowBlank: false,
            allowNode: false, // boolean
            allowMulti: false,
            allowLoop: false,
            allowEdge: false,
            allowPort: true,
            highlight: true,
            createEdge() {
                return this.createEdge({
                    attrs: {
                        line: {
                            stroke: '#8f8f8f',
                            strokeWidth: 1,
                        },
                    },
                })
            },
            validateMagnet({ magnet }) {
                // 节点上方的连接桩无法创建连线
                return magnet.getAttribute('port-group') === 'right'
            },
            validateConnection({
                                   sourceCell,
                                   targetCell,
                                   sourceMagnet,
                                   targetMagnet,
                               }) {
                // 不能连接自身
                if (sourceCell === targetCell) {
                    return false
                }

                // 只能从 bottom 连接桩开始连接，连接到 top 连接桩
                if (!sourceMagnet || sourceMagnet.getAttribute('port-group') === 'left') {
                    return false
                }

                if (!targetMagnet || targetMagnet.getAttribute('port-group') !== 'left') {
                    return false
                }

                // 不能重复连线
                // const edges = this.getEdges()
                // const portId = targetMagnet.getAttribute('port')
                // if (edges.find((edge) => edge.getTargetPortId() === portId)) {
                //   return false
                // }

                return true
            },
        },
        highlighting: {
            // 连接桩可以被连接时在连接桩外围围渲染一个包围框
            magnetAvailable: {
                name: 'stroke',
                args: {
                    attrs: {
                        fill: '#fff',
                        stroke: '#A4DEB1',
                        strokeWidth: 4,
                    },
                },
            },
            // 连接桩吸附连线时在连接桩外围围渲染一个包围框
            magnetAdsorbed: {
                name: 'stroke',
                args: {
                    attrs: {
                        fill: '#fff',
                        stroke: '#31d0c6',
                        strokeWidth: 4,
                    },
                },
            }
        },
    })
}

/**
 * 初始化编辑画板
 */
export const initEditGraph = (graphDom: HTMLElement, taskInfo: TaskInfo):Graph => {
    const graph:Graph = buildEditGraph(graphDom)

    if(taskInfo.flowData){
        graph.fromJSON(JSON.parse(taskInfo.flowData))
        graph.getNodes().forEach(i => {
            i.data.status = NodeStatus.INIT
        })
    }

    graph.centerContent()
    graph.use(
        new Snapline({
            enabled: true,
        })
    )
    graph.use(
        new Selection({
            enabled: true,
            multiple: false,
            rubberband: true,
            movable: false,
            showNodeSelectionBox: true,
            pointerEvents: 'none',
            modifiers: 'shift'
        })
    )
    return graph
}

/**
 * 创建节点面板
 */
const buildStencil = (graph: Graph) => {
    return new Stencil({
        title: stencilTitle,
        target: graph,
        stencilGraphHeight: 0,
        stencilGraphWidth: 250,
        groups: [stencilGroup],
        layoutOptions:{
            columns: 1,
            dx: 60
        }
    })
}

/**
 * 初始化节点面板
 */
export const initStencil = (stencilDom: HTMLElement, graph: Graph) => {
    const nodes = nodeTemplateList.map(i => {
        return graph.createNode({
            shape: shapeName,
            data: i
        })
    })
    const stencil = buildStencil(graph)
    stencil.load(nodes, stencilGroup.name)
    stencilDom.appendChild(stencil.container)
}

/**
 * 创建预览画板
 */
const buildViewGraph = (graphDom: HTMLElement) :Graph => {
    return new Graph({
        container: graphDom,
        autoResize: true,
        background: {
            color: '#ffffff',
        },
        interacting: false,
    })
}

/**
 * 初始化预览画板
 */
export const initViewGraph = (graphDom: HTMLElement, taskInfo: TaskInfo) :Graph => {
    const graph = buildViewGraph(graphDom)

    if(taskInfo.flowData){
        graph.fromJSON(JSON.parse(taskInfo.flowData))
        graph.getNodes().forEach((i, index) => {
            if(index === 0){
                const leftPort = i.getPorts().find(i => i.group === 'left')
                i.removePort(leftPort?.id as string)
            }
            if(index === graph.getNodes().length - 1){
                const leftPort = i.getPorts().find(i => i.group === 'right')
                i.removePort(leftPort?.id as string)
            }
            taskInfo.taskDataList.forEach(t => {
                if(i.id == t.id){
                    i.data = t
                }
            })
        })
    }

    graph.zoomToFit({ padding: 10, maxScale: 1 })
    graph.centerContent()
    return graph
}